package typedefault

import (
	"bufio"
	"codejy/analysis"
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"net"
	"strconv"
	"strings"
)

type Socket struct {
	Addr        string
	ThreadStore *structdef.ThreadStore
	Address     string //客户端或者服务端的地址
	Listener    net.Listener
	Conn        net.Conn
	Reader      *bufio.Reader
	mode        string //模式
}

// 创建实例
func (a *Socket) CreateTypeDefault(addr string, threadStore *structdef.ThreadStore, parameter ...string) {
	address := parameter[0]
	if address == "" {
		panic("new(Socket,?)参数不能为空,必须是地址:127.0.0.1:8080")
	}

	instance := &Socket{
		Addr:        addr,
		ThreadStore: threadStore,
		Address:     address,
	}
	mode := parameter[1]
	if mode == "server" {
		instance.server()
	} else if mode == "client" {
		instance.client()
	} else {
		panic("new(Socket,?)参数不能为空,必须是server或者client")
	}
	store.AddTypeDefaultInstanceStore(threadStore, a.GetTypeName(), addr, instance)
}

func (a *Socket) ParameterProcessing(parameter []string) []string {
	//排除前后""
	for i := range parameter {
		s := parameter[i]
		if strings.HasPrefix(s, "\"") && strings.HasSuffix(s, "\"") {
			s = s[1 : len(s)-1]
			parameter[i] = s
		}
	}
	return parameter
}

func (a *Socket) GetData() interface{} {
	return ""
}

func (a *Socket) ToStr() string {
	return ""
}
func (a *Socket) server() {
	listener, err := net.Listen("tcp", a.Address)
	if err != nil {
		panic(err)
	}
	a.Listener = listener
}

func (a *Socket) client() {
	conn, err := net.Dial("tcp", a.Address)
	if err != nil {
		panic(err)
	}
	a.Conn = conn
}

func (a *Socket) Accept() string {
	conn, err := a.Listener.Accept()
	if err != nil {
		//判断是否是关闭连接
		if strings.Contains(err.Error(), "use of closed network connection") {
			return "false"
		} else {
			panic(err)
		}
	}
	a.Conn = conn
	//创建一个网络连接数据的读取器,这个读取器是缓存的可以多次读取
	a.Reader = bufio.NewReader(conn)
	return "true"
}

// 根据客户端发送的数据返回 ,客户端发送的是字节容器,那么返回的也是字节容器对象,客户端发送的是字符串,那么返回的也是字符串
func (a *Socket) Read() string {
	buffer := make([]byte, 16)
	n, err := a.Reader.Read(buffer)
	if err != nil {
		panic(err)
	}
	//获取需要读取的长度
	padding := utils.UnBytePadding(buffer[:n])
	s := string(padding)
	//按照_分割
	split := strings.Split(s, "_")
	atoi, err := strconv.Atoi(split[0])
	if err != nil {
		panic(err)
	}
	//读取数据
	buffer = make([]byte, atoi)
	_, err1 := a.Reader.Read(buffer)
	if err1 != nil {
		panic(err1)
	}
	s2 := split[1]
	if s2 == "s" { //字符串
		return string(buffer)
	}
	//二进制容器
	return globalfunc.ExecuteFunc("TransitionBytes", buffer, a.ThreadStore).(string)
}

func (a *Socket) Write(data string) {
	var len1 int
	var data0 = []byte(data)
	var pdBy = "s"
	//判断是否是地址
	if analysis.IsInstanceAddress(data) {
		//判断是否是Bytes
		pd, typeName := store.GetTypeDefaultInstanceInversionStore(a.ThreadStore, data)
		if !pd || typeName != "Bytes" {
			panic("Socket.write()参数必须是字符串,数值,布尔或者Bytes")
		}
		value4, _ := GetTypeDefaultValue[[]byte](a.ThreadStore, "Bytes", data)
		len1 = len(value4)
		data0 = value4
		pdBy = "b"
	} else {
		len1 = len(data)
		pdBy = "s"
	}
	var preBytes = utils.BytePadding([]byte(strconv.Itoa(len1)+"_"+pdBy), 16)
	//合并
	var data1 = append(preBytes, data0...)
	_, err := a.Conn.Write(data1)
	if err != nil {
		panic(err)
	}
}

// 结束会话
func (a *Socket) SessionClose() {
	a.Conn.Close()
}

// 结束监听
func (a *Socket) CloseServer() {
	a.Conn.Close()
	a.Listener.Close()
}

func (f *Socket) GetDef() string {
	return `
		@CodeManual(def="new("Socket")",des="创建Socket实例")
		type Socket{
			def init{
				core&CreateTypeDefault($1,$2)
			}
			@CodeManual(def="accept()",des="接受客户端连接")
			def accept{
				to core&Accept()
			}
			@CodeManual(def="read()",des="读取客户端发送的数据,返回字符串或者Bytes")
			def read{
				to core&Read()
			}
			@CodeManual(def="write(?)",des="向客户端发送数据,参数必须是字符串,数值,布尔或者Bytes")
			def write{
				core&Write($1)
			}
			@CodeManual(def="close()",des="结束会话")
			def close{
				core&SessionClose()
			}
			@CodeManual(def="closeServer()",des="结束监听")
			def exit{
				core&CloseServer()
			}
		}
	`
}
func init() {
	RegisterTypeDefault(&Socket{})
}

func (f *Socket) GetTypeName() string {
	return "Socket"
}
